/*
 * @Author: 码农 2646995216@qq.com
 * @Date: 2025-03-18 15:13:58
 * @LastEditors: 码农 2646995216@qq.com
 * @LastEditTime: 2025-03-18 23:49:48
 * @FilePath: /netcomputer/socket.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

using namespace std;

enum
{
	Socket_false = 1, // 创建套接字失败
	Bind_false,		  // 绑定失败
	Listen_false,	  // 监听失败
	Accept_false,	  // 等待客户端连接失败
	Connect_false,	  // 连接服务器失败
};

const int backlog = 5;

class Sock
{
public:
	// 构造函数
	Sock(int listensockfd = -1)
		: _listensockfd(listensockfd)
	{
	}

	// 创建套接字
	void Socket()
	{
		_listensockfd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET：代表IPv4，SOCK_STREAM：代表Tcp协议
		if (_listensockfd < 0)
		{
			cout << "socket false" << endl;
			exit(Socket_false);
		}
		cout << "socket success" << endl;

	}

	// 绑定，传端口号，是因为sockaddr_in需要，用来保存客户端的IP地址和端口号
	void Bind(uint16_t port)
	{
		sockaddr_in local;
		memset(&local, 0, sizeof(&local)); // 初始化

		local.sin_family = AF_INET;
		local.sin_port = htons(port);		// 将端口号转化为网络字节序
		local.sin_addr.s_addr = INADDR_ANY; // 代表0.0.0.0

		socklen_t len = sizeof(local);
		int n = bind(_listensockfd, (struct sockaddr *)&local, len);
		if (n < 0)
		{
			cout << "bind false" << endl;
			exit(Bind_false);
		}
		cout << "bind success" << endl;
	}

	// 监听
	void Listen()
	{
		int n = listen(_listensockfd, backlog);
		if (n < 0)
		{
			cout << "listen false" << endl;
			exit(Listen_false);
		}
		cout << "listen success" << endl;
	}

	// 如果没有客户端连接服务端，则accept会阻塞等待新连接，等待客户端的连接
	// 可以通过Accept函数，拿到客户端的ip地址，端口号，用于网络通信的描述符sock
	int Accept(string &clientip, uint16_t &clientport)
	{
		sockaddr_in addr;
		socklen_t len = sizeof(addr);
		// 调用accpt函数，会将客户端的数据保存在addr中(ip,port)
		int sock = accept(_listensockfd, (struct sockaddr *)&addr, &len);
		if (sock < 0)
		{
			cout << "accept false" << endl;
			exit(Accept_false);
		}
		cout << "accept success" << endl;

		// 将客户端的ip和port，放入
		clientip = inet_ntoa(addr.sin_addr); // 将in_addr_t类型的ip转为char*类型的ip
		clientport = ntohs(addr.sin_port);	 // 将其转为主机字节序

		return sock;
	}

	// 连接服务器，这个ip和port是我们在启动客户端的时候输入的
	bool Connect(string &ip, uint16_t &port)
	{
		sockaddr_in peer;
		memset(&peer, 0, sizeof(peer));//初始化
		peer.sin_family = AF_INET;
		peer.sin_addr.s_addr = inet_addr(ip.c_str());
		peer.sin_port = htons(port);

		socklen_t len = sizeof(peer);
		int n = connect(_listensockfd, (struct sockaddr *)&peer, len);
		if (n < 0)
		{
			cout << "connect false" << endl;
			//exit(Connect_false);
			return false;
		}
		cout << "connect success" << endl;

		return true;
	}

	//关闭网络文件适配符
	void Close()
	{
		close(_listensockfd);
	}

	//获取网络文件适配符
	int Getlistensockfd()
	{
		return _listensockfd;
	}

	// 析构函数
	~Sock()
	{
	}

private:
	int _listensockfd; // 网络文件适配符
};